home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Utilities / Calc / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-10  |  25.6 KB  |  1,269 lines  |  [TEXT/????]

  1. /*
  2.  * Copyright (c) 1992 David I. Bell
  3.  * Permission is granted to use, distribute, or modify this source,
  4.  * provided that this copyright notice remains intact.
  5.  *
  6.  * Scanf and printf routines for extended precision numbers
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include "xstdarg.h"
  11. #include "xmath.h"
  12.  
  13. #define    OUTBUFSIZE    200        /* realloc size for output buffers */
  14.  
  15.  
  16. #define    PUTCHAR(ch)        math_chr(ch)
  17. #define    PUTSTR(str)        math_str(str)
  18. #define    PRINTF1(fmt, a1)    math_fmt(fmt, a1)
  19. #define    PRINTF2(fmt, a1, a2)    math_fmt(fmt, a1, a2)
  20.  
  21.  
  22. long    _outdigits_ = 20;        /* default digits for output */
  23. int    _outmode_ = MODE_INITIAL;    /* default output mode */
  24.  
  25.  
  26. /*
  27.  * Output state that has been saved when diversions are done.
  28.  */
  29. typedef struct iostate IOSTATE;
  30. struct iostate {
  31.     IOSTATE *oldiostates;        /* previous saved state */
  32.     long outdigits;            /* digits for output */
  33.     int outmode;            /* output mode */
  34.     FILE *outfp;            /* file unit for output (if any) */
  35.     char *outbuf;            /* output string buffer (if any) */
  36.     long outbufsize;        /* current size of string buffer */
  37.     long outbufused;        /* space used in string buffer */
  38.     BOOL outputisstring;        /* TRUE if output is to string buffer */
  39. };
  40.  
  41.  
  42. static IOSTATE    *oldiostates = NULL;    /* list of saved output states */
  43. static FILE    *outfp = stdout;    /* file unit for output */
  44. static char    *outbuf = NULL;        /* current diverted buffer */
  45. static long    scalefactor;
  46. static long    outbufsize;
  47. static long    outbufused;
  48. static BOOL    outputisstring;
  49. static ZVALUE    scalenumber = { 0, 0, 0 };
  50.  
  51. #if 0
  52. static long    etoalen;
  53. static char    *etoabuf = NULL;
  54. #endif
  55.  
  56. static void zprintx proto((ZVALUE z, long width));
  57. static void zprintb proto((ZVALUE z, long width));
  58. static void zprinto proto((ZVALUE z, long width));
  59. static void zprintval proto((ZVALUE z, long decimals, long width));
  60.  
  61. static void atoz proto((char * s, ZVALUE * res));
  62.  
  63. static void qprintff();
  64. static void qprintfd();
  65. static void qprintfe();
  66. static void qprintfr();
  67. static void qprintfo();
  68. static void qprintfb();
  69. #ifdef CODE
  70. extern void qprintfx();
  71. #else
  72. static void qprintfx();
  73. #endif
  74.  
  75.  
  76. /*
  77.  * Routine to output a character either to a FILE
  78.  * handle or into a string.
  79.  */
  80. void
  81. math_chr(ch)
  82. {
  83.     char    *cp;
  84.  
  85.     if (!outputisstring) {
  86.         fputc(ch, outfp);
  87.         return;
  88.     }
  89.     if (outbufused >= outbufsize) {
  90.         cp = (char *)realloc(outbuf, outbufsize + OUTBUFSIZE + 1);
  91.         if (cp == NULL)
  92.             error("Cannot realloc output string");
  93.         outbuf = cp;
  94.         outbufsize += OUTBUFSIZE;
  95.     }
  96.     outbuf[outbufused++] = (char)ch;
  97. }
  98.  
  99.  
  100. /*
  101.  * Routine to output a null-terminated string either
  102.  * to a FILE handle or into a string.
  103.  */
  104. void
  105. math_str(str)
  106.     char    *str;
  107. {
  108.     char    *cp;
  109.     int    len;
  110.  
  111.     if (!outputisstring) {
  112.         fputs(str, outfp);
  113.         return;
  114.     }
  115.     len = strlen(str);
  116.     if ((outbufused + len) > outbufsize) {
  117.         cp = (char *)realloc(outbuf, outbufsize + len + OUTBUFSIZE + 1);
  118.         if (cp == NULL)
  119.             error("Cannot realloc output string");
  120.         outbuf = cp;
  121.         outbufsize += (len + OUTBUFSIZE);
  122.     }
  123.     memcpy(&outbuf[outbufused], str, len);
  124.     outbufused += len;
  125. }
  126.  
  127.  
  128. /*
  129.  * Routine to output a printf-style formatted string either
  130.  * to a FILE handle or into a string.
  131.  */
  132. #ifdef VARARGS
  133. # define VA_ALIST fmt, va_alist
  134. # define VA_DCL char *fmt; va_dcl
  135. #else
  136. # ifdef __STDC__
  137. #  define VA_ALIST char *fmt, ...
  138. #  define VA_DCL
  139. # else
  140. #  define VA_ALIST fmt
  141. #  define VA_DCL char *fmt;
  142. # endif
  143. #endif
  144. /*VARARGS*/
  145. void
  146. math_fmt(VA_ALIST)
  147.     VA_DCL
  148. {
  149.     va_list ap;
  150.     char buf[200];
  151.  
  152. #ifdef VARARGS
  153.     va_start(ap);
  154. #else
  155.     va_start(ap, fmt);
  156. #endif
  157.     vsprintf(buf, fmt, ap);
  158.     va_end(ap);
  159.     math_str(buf);
  160. }
  161.  
  162.  
  163. /*
  164.  * Flush the current output stream.
  165.  */
  166. void
  167. math_flush()
  168. {
  169.     if (!outputisstring)
  170.         fflush(outfp);
  171. }
  172.  
  173.  
  174. /*
  175.  * Divert further output so that it is saved into a string that will be
  176.  * returned later when the diversion is completed.  The current state of
  177.  * output is remembered for later restoration.  Diversions can be nested.
  178.  * Output diversion is only intended for saving output to "stdout".
  179.  */
  180. void
  181. divertio()
  182. {
  183.     register IOSTATE *sp;
  184.  
  185.     sp = (IOSTATE *) malloc(sizeof(IOSTATE));
  186.     if (sp == NULL)
  187.         error("No memory for diverting output");
  188.     sp->oldiostates = oldiostates;
  189.     sp->outdigits = _outdigits_;
  190.     sp->outmode = _outmode_;
  191.     sp->outfp = outfp;
  192.     sp->outbuf = outbuf;
  193.     sp->outbufsize = outbufsize;
  194.     sp->outbufused = outbufused;
  195.     sp->outputisstring = outputisstring;
  196.  
  197.     outbufused = 0;
  198.     outbufsize = 0;
  199.     outbuf = (char *) malloc(OUTBUFSIZE + 1);
  200.     if (outbuf == NULL)
  201.         error("Cannot allocate divert string");
  202.     outbufsize = OUTBUFSIZE;
  203.     outputisstring = TRUE;
  204.     oldiostates = sp;
  205. }
  206.  
  207.  
  208. /*
  209.  * Undivert output and return the saved output as a string.  This also
  210.  * restores the output state to what it was before the diversion began.
  211.  * The string needs freeing by the caller when it is no longer needed.
  212.  */
  213. char *
  214. getdivertedio()
  215. {
  216.     register IOSTATE *sp;
  217.     char *cp;
  218.  
  219.     sp = oldiostates;
  220.     if (sp == NULL)
  221.         error("No diverted state to restore");
  222.     cp = outbuf;
  223.     cp[outbufused] = '\0';
  224.     oldiostates = sp->oldiostates;
  225.     _outdigits_ = sp->outdigits;
  226.     _outmode_ = sp->outmode;
  227.     outfp = sp->outfp;
  228.     outbuf = sp->outbuf;
  229.     outbufsize = sp->outbufsize;
  230.     outbufused = sp->outbufused;
  231.     outbuf = sp->outbuf;
  232.     outputisstring = sp->outputisstring;
  233.     return cp;
  234. }
  235.  
  236.  
  237. /*
  238.  * Clear all diversions and set output back to the original destination.
  239.  * This is called when resetting the global state of the program.
  240.  */
  241. void
  242. cleardiversions()
  243. {
  244.     while (oldiostates)
  245.         free(getdivertedio());
  246. }
  247.  
  248.  
  249. /*
  250.  * Set the output routines to output to the specified FILE stream.
  251.  * This interacts with output diversion in the following manner.
  252.  *    STDOUT    diversion    action
  253.  *    ----    ---------    ------
  254.  *    yes    yes        set output to diversion string again.
  255.  *    yes    no        set output to stdout.
  256.  *    no    yes        set output to specified file.
  257.  *    no    no        set output to specified file.
  258.  */
  259. void
  260. setfp(newfp)
  261.     FILE *newfp;
  262. {
  263.     outfp = newfp;
  264.     outputisstring = (oldiostates && (newfp == stdout));
  265. }
  266.  
  267.  
  268. /*
  269.  * Set the output mode for numeric output.
  270.  */
  271. void
  272. setmode(newmode)
  273. {
  274.     if ((newmode <= MODE_DEFAULT) || (newmode > MODE_MAX))
  275.         error("Setting illegal output mode");
  276.     _outmode_ = newmode;
  277. }
  278.  
  279.  
  280. /*
  281.  * Set the number of digits for float or exponential output.
  282.  */
  283. void
  284. setdigits(newdigits)
  285.     long newdigits;
  286. {
  287.     if (newdigits < 0)
  288.         error("Setting illegal number of digits");
  289.     _outdigits_ = newdigits;
  290. }
  291.  
  292.  
  293. /*
  294.  * Print a formatted string containing arbitrary numbers, similar to printf.
  295.  * ALL numeric arguments to this routine are rational NUMBERs.
  296.  * Various forms of printing such numbers are supplied, in addition
  297.  * to strings and characters.  Output can actually be to any FILE
  298.  * stream or a string.
  299.  */
  300. #ifdef VARARGS
  301. # define VA_ALIST1 fmt, va_alist
  302. # define VA_DCL1 char *fmt; va_dcl
  303. #else
  304. # ifdef __STDC__
  305. #  define VA_ALIST1 char *fmt, ...
  306. #  define VA_DCL1
  307. # else
  308. #  define VA_ALIST1 fmt
  309. #  define VA_DCL1 char *fmt;
  310. # endif
  311. #endif
  312. /*VARARGS*/
  313. void
  314. qprintf(VA_ALIST1)
  315.     VA_DCL1
  316. {
  317.     va_list ap;
  318.     NUMBER *q;
  319.     int ch, sign;
  320.     long width, precision;
  321.  
  322. #ifdef VARARGS
  323.     va_start(ap);
  324. #else
  325.     va_start(ap, fmt);
  326. #endif
  327.     while ((ch = *fmt++) != '\0') {
  328.         if (ch == '\\') {
  329.             ch = *fmt++;
  330.             switch (ch) {
  331.                 case 'n': ch = '\n'; break;
  332.                 case 'r': ch = '\r'; break;
  333.                 case 't': ch = '\t'; break;
  334.                 case 'f': ch = '\f'; break;
  335.                 case 'v': ch = '\v'; break;
  336.                 case 'b': ch = '\b'; break;
  337.                 case 0:
  338.                     va_end(ap);
  339.                     return;
  340.             }
  341.             PUTCHAR(ch);
  342.             continue;
  343.         }
  344.         if (ch != '%') {
  345.             PUTCHAR(ch);
  346.             continue;
  347.         }
  348.         ch = *fmt++;
  349.         width = 0; precision = 8; sign = 1;
  350. percent:    ;
  351.         switch (ch) {
  352.             case 'd':
  353.                 q = va_arg(ap, NUMBER *);
  354.                 qprintfd(q, width);
  355.                 break;
  356.             case 'f':
  357.                 q = va_arg(ap, NUMBER *);
  358.                 qprintff(q, width, precision);
  359.                 break;
  360.             case 'e':
  361.                 q = va_arg(ap, NUMBER *);
  362.                 qprintfe(q, width, precision);
  363.                 break;
  364.             case 'r':
  365.             case 'R':
  366.                 q = va_arg(ap, NUMBER *);
  367.                 qprintfr(q, width, (BOOL) (ch == 'R'));
  368.                 break;
  369.             case 'N':
  370.                 q = va_arg(ap, NUMBER *);
  371.                 zprintval(q->num, 0L, width);
  372.                 break;
  373.             case 'D':
  374.                 q = va_arg(ap, NUMBER *);
  375.                 zprintval(q->den, 0L, width);
  376.                 break;
  377.             case 'o':
  378.                 q = va_arg(ap, NUMBER *);
  379.                 qprintfo(q, width);
  380.                 break;
  381.             case 'x':
  382.                 q = va_arg(ap, NUMBER *);
  383.                 qprintfx(q, width);
  384.                 break;
  385.             case 'b':
  386.                 q = va_arg(ap, NUMBER *);
  387.                 qprintfb(q, width);
  388.                 break;
  389.             case 's':
  390.                 PUTSTR(va_arg(ap, char *));
  391.                 break;
  392.             case 'c':
  393.                 PUTCHAR(va_arg(ap, int));
  394.                 break;
  395.             case 0:
  396.                 va_end(ap);
  397.                 return;
  398.             case '-':
  399.                 sign = -1;
  400.                 ch = *fmt++;
  401.             default:
  402.         if (('0' <= ch && ch <= '9') || ch == '.' || ch == '*') {
  403.             if (ch == '*') {
  404.                 q = va_arg(ap, NUMBER *);
  405.                 width = sign * qtoi(q);
  406.                 ch = *fmt++;
  407.             } else if (ch != '.') {
  408.                 width = ch - '0';
  409.                 while ('0' <= (ch = *fmt++) && ch <= '9')
  410.                     width = width * 10 + ch - '0';
  411.                 width *= sign;
  412.             }
  413.             if (ch == '.') {
  414.                 if ((ch = *fmt++) == '*') {
  415.                     q = va_arg(ap, NUMBER *);
  416.                     precision = qtoi(q);
  417.                     ch = *fmt++;
  418.                 } else {
  419.                     precision = 0;
  420.                     while ('0' <= (ch = *fmt++) && ch <= '9')
  421.                         precision = precision * 10 + ch - '0';
  422.                 }
  423.             }
  424.             goto percent;
  425.         }
  426.         }
  427.     }
  428.     va_end(ap);
  429. }
  430.  
  431.  
  432. #if 0
  433. /*
  434.  * Read a number from the specified FILE stream (NULL means stdin).
  435.  * The number can be an integer, a fraction, a real number, an
  436.  * exponential number, or a hex, octal or binary number.  Leading blanks
  437.  * are skipped.  Illegal numbers return NULL.  Unrecognized characters
  438.  * remain to be read on the line.
  439.  *    q = qreadval(fp);
  440.  */
  441. NUMBER *
  442. qreadval(fp)
  443.     FILE *fp;        /* file stream to read from (or NULL) */
  444. {
  445.     NUMBER *r;        /* returned number */
  446.     char *cp;         /* current buffer location */
  447.     long savecc;        /* characters saved in buffer */
  448.     long scancc;         /* characters parsed correctly */
  449.     int ch;            /* current character */
  450.  
  451.     if (fp == NULL)
  452.         fp = stdin;
  453.     if (etoabuf == NULL) {
  454.         etoabuf = (char *)malloc(OUTBUFSIZE + 2);
  455.         if (etoabuf == NULL)
  456.             return NULL;
  457.         etoalen = OUTBUFSIZE;
  458.     }
  459.     cp = etoabuf;
  460.     ch = fgetc(fp);
  461.     while ((ch == ' ') || (ch == '\t'))
  462.         ch = fgetc(fp);
  463.     savecc = 0;
  464.     for (;;) {
  465.         if (ch == EOF)
  466.             return NULL;
  467.         if (savecc >= etoalen)
  468.         {
  469.             cp = (char *)realloc(etoabuf, etoalen + OUTBUFSIZE + 2);
  470.             if (cp == NULL)
  471.                 return NULL;
  472.             etoabuf = cp;
  473.             etoalen += OUTBUFSIZE;
  474.             cp += savecc;
  475.         }
  476.         *cp++ = (char)ch;
  477.         *cp = '\0';
  478.         scancc = qparse(etoabuf, QPF_SLASH);
  479.         if (scancc != ++savecc)
  480.             break;
  481.         ch = fgetc(fp);
  482.     }
  483.     ungetc(ch, fp);
  484.     if (scancc < 0)
  485.         return NULL;
  486.     r = atoq(etoabuf);
  487.     if (iszero(r->den)) {
  488.         qfree(r);
  489.         r = NULL;
  490.     }
  491.     return r;
  492. }
  493. #endif
  494.  
  495.  
  496. /*
  497.  * Print a complex number in rational representation.
  498.  * Example:  2/3-4i/5
  499.  */
  500. void
  501. cprintfr(c)
  502.     COMPLEX *c;
  503. {
  504.     NUMBER *r;
  505.     NUMBER *i;
  506.  
  507.     r = c->real;
  508.     i = c->imag;
  509.     if (!qiszero(r) || qiszero(i))
  510.         qprintfr(r, 0L, FALSE);
  511.     if (qiszero(i))
  512.         return;
  513.     if (!qiszero(r) && !qisneg(i))
  514.         PUTCHAR('+');
  515.     zprintval(i->num, 0L, 0L);
  516.     PUTCHAR('i');
  517.     if (qisfrac(i)) {
  518.         PUTCHAR('/');
  519.         zprintval(i->den, 0L, 0L);
  520.     }
  521. }
  522.  
  523.  
  524. /*
  525.  * Print a number in the specified output mode.
  526.  * If MODE_DEFAULT is given, then the default output mode is used.
  527.  * Any approximate output is flagged with a leading tilde.
  528.  * Integers are always printed as themselves.
  529.  */
  530. void
  531. qprintnum(q, outmode)
  532.     NUMBER *q;
  533. {
  534.     NUMBER tmpval;
  535.     long prec, exp;
  536.  
  537.     if (outmode == MODE_DEFAULT)
  538.         outmode = _outmode_;
  539.     if ((outmode == MODE_FRAC) || ((outmode == MODE_REAL) && qisint(q))) {
  540.         qprintfr(q, 0L, FALSE);
  541.         return;
  542.     }
  543.     switch (outmode) {
  544.         case MODE_INT:
  545.             if (qisfrac(q))
  546.                 PUTCHAR('~');
  547.             qprintfd(q, 0L);
  548.             break;
  549.  
  550.         case MODE_REAL:
  551.             prec = qplaces(q);
  552.             if ((prec < 0) || (prec > _outdigits_)) {
  553.                 prec = _outdigits_;
  554.                 PUTCHAR('~');
  555.             }
  556.             qprintff(q, 0L, prec);
  557.             break;
  558.  
  559.         case MODE_EXP:
  560.             if (qiszero(q)) {
  561.                 PUTCHAR('0');
  562.                 return;
  563.             }
  564.             tmpval = *q;
  565.             tmpval.num.sign = 0;
  566.             exp = qilog10(&tmpval);
  567.             if (exp == 0) {        /* in range to output as real */
  568.                 qprintnum(q, MODE_REAL);
  569.                 return;
  570.             }
  571.             tmpval.num = _one_;
  572.             tmpval.den = _one_;
  573.             if (exp > 0)
  574.                 ztenpow(exp, &tmpval.den);
  575.             else
  576.                 ztenpow(-exp, &tmpval.num);
  577.             q = qmul(q, &tmpval);
  578.             freeh(tmpval.num.v);
  579.             freeh(tmpval.den.v);
  580.             qprintnum(q, MODE_REAL);
  581.             qfree(q);
  582.             PRINTF1("e%ld", exp);
  583.             break;
  584.  
  585.         case MODE_HEX:
  586.             qprintfx(q, 0L);
  587.             break;
  588.  
  589.         case MODE_OCTAL:
  590.             qprintfo(q, 0L);
  591.             break;
  592.  
  593.         case MODE_BINARY:
  594.             qprintfb(q, 0L);
  595.             break;
  596.  
  597.         default:
  598.             error("Bad mode for print");
  599.     }
  600. }
  601.  
  602.  
  603. /*
  604.  * Print a number in floating point representation.
  605.  * Example:  193.784
  606.  */
  607. static void
  608. qprintff(q, width, precision)
  609.     NUMBER *q;
  610.     long width;
  611.     long precision;
  612. {
  613.     ZVALUE z, z1;
  614.  
  615.     if (precision != scalefactor) {
  616.         if (scalenumber.v)
  617.             freeh(scalenumber.v);
  618.         ztenpow(precision, &scalenumber);
  619.         scalefactor = precision;
  620.     }
  621.     if (scalenumber.v)
  622.         zmul(q->num, scalenumber, &z);
  623.     else
  624.         z = q->num;
  625.     if (qisfrac(q)) {
  626.         zquo(z, q->den, &z1);
  627.         if (z.v != q->num.v)
  628.             freeh(z.v);
  629.         z = z1;
  630.     }
  631.     if (qisneg(q) && iszero(z))
  632.         PUTCHAR('-');
  633.     zprintval(z, precision, width);
  634.     if (z.v != q->num.v)
  635.         freeh(z.v);
  636. }
  637.  
  638.  
  639. /*
  640.  * Print a number in exponential notation.
  641.  * Example: 4.1856e34
  642.  */
  643. /*ARGSUSED*/
  644. static void
  645. qprintfe(q, width, precision)
  646.     register NUMBER *q;
  647.     long width;
  648.     long precision;
  649. {
  650.     long exponent;
  651.     NUMBER q2;
  652.     ZVALUE num, den, tenpow, tmp;
  653.  
  654.     if (qiszero(q)) {
  655.         PUTSTR("0.0");
  656.         return;
  657.     }
  658.     num = q->num;
  659.     den = q->den;
  660.     num.sign = 0;
  661.     exponent = zdigits(num) - zdigits(den);
  662.     if (exponent > 0) {
  663.         ztenpow(exponent, &tenpow);
  664.         zmul(den, tenpow, &tmp);
  665.         freeh(tenpow.v);
  666.         den = tmp;
  667.     }
  668.     if (exponent < 0) {
  669.         ztenpow(-exponent, &tenpow);
  670.         zmul(num, tenpow, &tmp);
  671.         freeh(tenpow.v);
  672.         num = tmp;
  673.     }
  674.     if (zrel(num, den) < 0) {
  675.         zmuli(num, 10L, &tmp);
  676.         if (num.v != q->num.v)
  677.             freeh(num.v);
  678.         num = tmp;
  679.         exponent--;
  680.     }
  681.     q2.num = num;
  682.     q2.den = den;
  683.     q2.num.sign = q->num.sign;
  684.     qprintff(&q2, 0L, precision);
  685.     if (exponent)
  686.         PRINTF1("e%ld", exponent);
  687.     if (num.v != q->num.v)
  688.         freeh(num.v);
  689.     if (den.v != q->den.v)
  690.         freeh(den.v);
  691. }
  692.  
  693.  
  694. /*
  695.  * Print a number in rational representation.
  696.  * Example: 397/37
  697.  */
  698. static void
  699. qprintfr(q, width, force)
  700.     NUMBER *q;
  701.     long width;
  702.     BOOL force;
  703. {
  704.     zprintval(q->num, 0L, width);
  705.     if (force || qisfrac(q)) {
  706.         PUTCHAR('/');
  707.         zprintval(q->den, 0L, width);
  708.     }
  709. }
  710.  
  711.  
  712. /*
  713.  * Print a number as an integer (truncating fractional part).
  714.  * Example: 958421
  715.  */
  716. static void
  717. qprintfd(q, width)
  718.     NUMBER *q;
  719.     long width;
  720. {
  721.     ZVALUE z;
  722.  
  723.     if (qisfrac(q)) {
  724.         zquo(q->num, q->den, &z);
  725.         zprintval(z, 0L, width);
  726.         freeh(z.v);
  727.     } else
  728.         zprintval(q->num, 0L, width);
  729. }
  730.  
  731.  
  732. /*
  733.  * Print a number in hex.
  734.  * This prints the numerator and denominator in hex.
  735.  */
  736. #ifndef CODE
  737. static 
  738. #endif
  739. void
  740. qprintfx(q, width)
  741.     NUMBER *q;
  742.     long width;
  743. {
  744.     zprintx(q->num, width);
  745.     if (qisfrac(q)) {
  746.         PUTCHAR('/');
  747.         zprintx(q->den, 0L);
  748.     }
  749. }
  750.  
  751.  
  752. /*
  753.  * Print a number in binary.
  754.  * This prints the numerator and denominator in binary.
  755.  */
  756. static void
  757. qprintfb(q, width)
  758.     NUMBER *q;
  759.     long width;
  760. {
  761.     zprintb(q->num, width);
  762.     if (qisfrac(q)) {
  763.         PUTCHAR('/');
  764.         zprintb(q->den, 0L);
  765.     }
  766. }
  767.  
  768.  
  769. /*
  770.  * Print a number in octal.
  771.  * This prints the numerator and denominator in octal.
  772.  */
  773. static void
  774. qprintfo(q, width)
  775.     NUMBER *q;
  776.     long width;
  777. {
  778.     zprinto(q->num, width);
  779.     if (qisfrac(q)) {
  780.         PUTCHAR('/');
  781.         zprinto(q->den, 0L);
  782.     }
  783. }
  784.  
  785.  
  786. /*
  787.  * Print an integer value as a hex number.
  788.  * The special characters 0x appear to indicate the number is hex.
  789.  */
  790. /*ARGSUSED*/
  791. static void
  792. zprintx(z, width)
  793.     ZVALUE z;
  794.     long width;
  795. {
  796.     register HALF *hp;    /* current word to print */
  797.     int len;        /* number of halfwords to type */
  798.  
  799.     len = z.len - 1;
  800.     if (isneg(z))
  801.         PUTCHAR('-');
  802.     if ((len == 0) && (*z.v <= (FULL) 9)) {
  803.         len = '0' + *z.v;
  804.         PUTCHAR(len);
  805.         return;
  806.     }
  807.     hp = z.v + len;
  808.     PRINTF1("0x%x", (FULL) *hp--);
  809.     while (--len >= 0)
  810.         PRINTF1("%04x", (FULL) *hp--);
  811. }
  812.  
  813.  
  814. /*
  815.  * Print an integer value as a binary number.
  816.  * The special characters 0b appear to indicate the number is binary.
  817.  */
  818. /*ARGSUSED*/
  819. static void
  820. zprintb(z, width)
  821.     ZVALUE z;
  822.     long width;
  823. {
  824.     register HALF *hp;    /* current word to print */
  825.     int len;        /* number of halfwords to type */
  826.     HALF val;        /* current value */
  827.     HALF mask;        /* current mask */
  828.     int didprint;        /* nonzero if printed some digits */
  829.     int ch;            /* current char */
  830.  
  831.     len = z.len - 1;
  832.     if (isneg(z))
  833.         PUTCHAR('-');
  834.     if ((len == 0) && (*z.v <= (FULL) 1)) {
  835.         len = '0' + *z.v;
  836.         PUTCHAR(len);
  837.         return;
  838.     }
  839.     hp = z.v + len;
  840.     didprint = 0;
  841.     PUTSTR("0b");
  842.     while (len-- >= 0) {
  843.         val = *hp--;
  844.         mask = (1 << (BASEB - 1));
  845.         while (mask) {
  846.             ch = '0' + ((mask & val) != 0);
  847.             if (didprint || (ch != '0')) {
  848.                 PUTCHAR(ch);
  849.                 didprint = 1;
  850.             }
  851.             mask >>= 1;
  852.         }
  853.     }
  854. }
  855.  
  856.  
  857. /*
  858.  * Print an integer value as an octal number.
  859.  * The number begins with a leading 0 to indicate that it is octal.
  860.  */
  861. /*ARGSUSED*/
  862. static void
  863. zprinto(z, width)
  864.     ZVALUE z;
  865.     long width;
  866. {
  867.     register HALF *hp;    /* current word to print */
  868.     int len;        /* number of halfwords to type */
  869.     int num1, num2;        /* numbers to type */
  870.     int rem;        /* remainder number of halfwords */
  871.  
  872.     if (isneg(z))
  873.         PUTCHAR('-');
  874.     len = z.len;
  875.     if ((len == 1) && (*z.v <= (FULL) 7)) {
  876.         num1 = '0' + *z.v;
  877.         PUTCHAR(num1);
  878.         return;
  879.     }
  880.     hp = z.v + len - 1;
  881.     rem = len % 3;
  882.     switch (rem) {    /* handle odd amounts first */
  883.         case 0:
  884.             num1 = (((FULL) hp[0]) << 8) + (((FULL) hp[-1]) >> 8);
  885.             num2 = (((FULL) (hp[-1] & 0xff)) << 16) + ((FULL) hp[-2]);
  886.             rem = 3;
  887.             break;
  888.         case 1:
  889.             num1 = 0;
  890.             num2 = (FULL) hp[0];
  891.             break;
  892.         case 2:
  893.             num1 = (((FULL) hp[0]) >> 8);
  894.             num2 = (((FULL) (hp[0] & 0xff)) << 16) + ((FULL) hp[-1]);
  895.             break;
  896.     }
  897.     if (num1)
  898.         PRINTF2("0%o%08o", num1, num2);
  899.     else
  900.         PRINTF1("0%o", num2);
  901.     len -= rem;
  902.     hp -= rem;
  903.     while (len > 0) {    /* finish in groups of 3 halfwords */
  904.         num1 = (((FULL) hp[0]) << 8) + (((FULL) hp[-1]) >> 8);
  905.         num2 = (((FULL) (hp[-1] & 0xff)) << 16) + ((FULL) hp[-2]);
  906.         PRINTF2("%08o%08o", num1, num2);
  907.         hp -= 3;
  908.         len -= 3;
  909.     }
  910. }
  911.  
  912.  
  913. /*
  914.  * Print a decimal integer to the terminal.
  915.  * This works by dividing the number by 10^2^N for some N, and
  916.  * then doing this recursively on the quotient and remainder.
  917.  * Decimals supplies number of decimal places to print, with a decimal
  918.  * point at the right location, with zero meaning no decimal point.
  919.  * Width is the number of columns to print the number in, including the
  920.  * decimal point and sign if required.  If zero, no extra output is done.
  921.  * If positive, leading spaces are typed if necessary. If negative, trailing
  922.  * spaces are typed if necessary.  As examples of the effects of these values,
  923.  * (345,0,0) = "345", (345,2,0) = "3.45", (345,5,8) = "  .00345".
  924.  */
  925. static void
  926. zprintval(z, decimals, width)
  927.     ZVALUE z;        /* number to be printed */
  928.     long decimals;        /* number of decimal places */
  929.     long width;        /* number of columns to print in */
  930. {
  931.     int depth;        /* maximum depth */
  932.     int n;            /* current index into array */
  933.     int i;            /* number to print */
  934.     long leadspaces;    /* number of leading spaces to print */
  935.     long putpoint;        /* digits until print decimal point */
  936.     long digits;        /* number of digits of raw number */
  937.     BOOL output;        /* TRUE if have output something */
  938.     BOOL neg;        /* TRUE if negative */
  939.     ZVALUE quo, rem;    /* quotient and remainder */
  940.     ZVALUE leftnums[32];    /* left parts of the number */
  941.     ZVALUE rightnums[32];    /* right parts of the number */
  942.  
  943.     if (decimals < 0)
  944.         decimals = 0;
  945.     if (width < 0)
  946.         width = 0;
  947.     neg = (z.sign != 0);
  948.  
  949.     leadspaces = width - neg - (decimals > 0);
  950.     z.sign = 0;
  951.     /*
  952.      * Find the 2^N power of ten which is greater than or equal
  953.      * to the number, calculating it the first time if necessary.
  954.      */
  955.     _tenpowers_[0] = _ten_;
  956.     depth = 0;
  957.     while ((_tenpowers_[depth].len < z.len) || (zrel(_tenpowers_[depth], z) <= 0)) {
  958.         depth++;
  959.         if (_tenpowers_[depth].len == 0)
  960.             zsquare(_tenpowers_[depth-1], &_tenpowers_[depth]);
  961.     }
  962.     /*
  963.      * Divide by smaller 2^N powers of ten until the parts are small
  964.      * enough to output.  This algorithm walks through a binary tree
  965.      * where each node is a piece of the number to print, and such that
  966.      * we visit left nodes first.  We do the needed recursion in line.
  967.      */
  968.     digits = 1;
  969.     output = FALSE;
  970.     n = 0;
  971.     putpoint = 0;
  972.     rightnums[0].len = 0;
  973.     leftnums[0] = z;
  974.     for (;;) {
  975.         while (n < depth) {
  976.             i = depth - n - 1;
  977.             zdiv(leftnums[n], _tenpowers_[i], &quo, &rem);
  978.             if (!iszero(quo))
  979.                 digits += (1L << i);
  980.             n++;
  981.             leftnums[n] = quo;
  982.             rightnums[n] = rem;
  983.         }
  984.         i = leftnums[n].v[0];
  985.         if (output || i || (n == 0)) {
  986.             if (!output) {
  987.                 output = TRUE;
  988.                 if (decimals > digits)
  989.                     leadspaces -= decimals;
  990.                 else
  991.                     leadspaces -= digits;
  992.                 while (--leadspaces >= 0)
  993.                     PUTCHAR(' ');
  994.                 if (neg)
  995.                     PUTCHAR('-');
  996.                 if (decimals) {
  997.                     putpoint = (digits - decimals);
  998.                     if (putpoint <= 0) {
  999.                         PUTCHAR('.');
  1000.                         while (++putpoint <= 0)
  1001.                             PUTCHAR('0');
  1002.                         putpoint = 0;
  1003.                     }
  1004.                 }
  1005.             }
  1006.             i += '0';
  1007.             PUTCHAR(i);
  1008.             if (--putpoint == 0)
  1009.                 PUTCHAR('.');
  1010.         }
  1011.         while (rightnums[n].len == 0) {
  1012.             if (n <= 0)
  1013.                 return;
  1014.             if (leftnums[n].len)
  1015.                 freeh(leftnums[n].v);
  1016.             n--;
  1017.         }
  1018.         freeh(leftnums[n].v);
  1019.         leftnums[n] = rightnums[n];
  1020.         rightnums[n].len = 0;
  1021.     }
  1022. }
  1023.  
  1024.  
  1025. /*
  1026.  * Convert a string to a number in rational, floating point,
  1027.  * exponential notation, hex, or octal.
  1028.  *    q = atoq(string);
  1029.  */
  1030. NUMBER *
  1031. atoq(s)
  1032.     register char *s;
  1033. {
  1034.     register NUMBER *q;
  1035.     register char *t;
  1036.     ZVALUE div, newnum, newden, tmp;
  1037.     long decimals, exp;
  1038.     BOOL hex, negexp;
  1039.  
  1040.     q = qalloc();
  1041.     decimals = 0;
  1042.     exp = 0;
  1043.     negexp = FALSE;
  1044.     hex = FALSE;
  1045.     t = s;
  1046.     if ((*t == '+') || (*t == '-'))
  1047.         t++;
  1048.     if ((*t == '0') && ((t[1] == 'x') || (t[1] == 'X'))) {
  1049.         hex = TRUE;
  1050.         t += 2;
  1051.     }
  1052.     while (((*t >= '0') && (*t <= '9')) || (hex &&
  1053.         (((*t >= 'a') && (*t <= 'f')) || ((*t >= 'A') && (*t <= 'F')))))
  1054.             t++;
  1055.     if (*t == '/') {
  1056.         t++;
  1057.         atoz(t, &q->den);
  1058.     } else if ((*t == '.') || (*t == 'e') || (*t == 'E')) {
  1059.         if (*t == '.') {
  1060.             t++;
  1061.             while ((*t >= '0') && (*t <= '9')) {
  1062.                 t++;
  1063.                 decimals++;
  1064.             }
  1065.         }
  1066.         /*
  1067.          * Parse exponent if any
  1068.          */
  1069.         if ((*t == 'e') || (*t == 'E')) {
  1070.             t++;
  1071.             if (*t == '+')
  1072.                 t++;
  1073.             else if (*t == '-') {
  1074.                 negexp = TRUE;
  1075.                 t++;
  1076.             }
  1077.             while ((*t >= '0') && (*t <= '9')) {
  1078.                 exp = (exp * 10) + *t++ - '0';
  1079.                 if (exp > 1000000)
  1080.                     error("Exponent too large");
  1081.             }
  1082.         }
  1083.         ztenpow(decimals, &q->den);
  1084.     }
  1085.     atoz(s, &q->num);
  1086.     if (qiszero(q)) {
  1087.         qfree(q);
  1088.         return qlink(&_qzero_);
  1089.     }
  1090.     /*
  1091.      * Apply the exponential if any
  1092.      */
  1093.     if (exp) {
  1094.         ztenpow(exp, &tmp);
  1095.         if (negexp) {
  1096.             zmul(q->den, tmp, &newden);
  1097.             freeh(q->den.v);
  1098.             q->den = newden;
  1099.         } else {
  1100.             zmul(q->num, tmp, &newnum);
  1101.             freeh(q->num.v);
  1102.             q->num = newnum;
  1103.         }
  1104.         freeh(tmp.v);
  1105.     }
  1106.     /*
  1107.      * Reduce the fraction to lowest terms
  1108.      */
  1109.     if (isunit(q->num) || isunit(q->den))
  1110.         return q;
  1111.     zgcd(q->num, q->den, &div);
  1112.     if (isunit(div))
  1113.         return q;
  1114.     zquo(q->num, div, &newnum);
  1115.     freeh(q->num.v);
  1116.     zquo(q->den, div, &newden);
  1117.     freeh(q->den.v);
  1118.     q->num = newnum;
  1119.     q->den = newden;
  1120.     return q;
  1121. }
  1122.  
  1123.  
  1124. /*
  1125.  * Read an integer value in decimal, hex, octal, or binary.
  1126.  * Hex numbers are indicated by a leading "0x", binary with a leading "0b",
  1127.  * and octal by a leading "0".  Periods are skipped over, but any other
  1128.  * extraneous character stops the scan.
  1129.  */
  1130. static void
  1131. atoz(s, res)
  1132.     register char *s;
  1133.     ZVALUE *res;
  1134. {
  1135.     ZVALUE z, ztmp, digit;
  1136.     HALF digval;
  1137.     BOOL minus;
  1138.     long shift;
  1139.  
  1140.     minus = FALSE;
  1141.     shift = 0;
  1142.     if (*s == '+')
  1143.         s++;
  1144.     else if (*s == '-') {
  1145.         minus = TRUE;
  1146.         s++;
  1147.     }
  1148.     if (*s == '0') {        /* possibly hex, octal, or binary */
  1149.         s++;
  1150.         if ((*s >= '0') && (*s <= '7')) {
  1151.             shift = 3;
  1152.         } else if ((*s == 'x') || (*s == 'X')) {
  1153.             shift = 4;
  1154.             s++;
  1155.         } else if ((*s == 'b') || (*s == 'B')) {
  1156.             shift = 1;
  1157.             s++;
  1158.         }
  1159.     }
  1160.     digit.v = &digval;
  1161.     digit.len = 1;
  1162.     digit.sign = 0;
  1163.     z = _zero_;
  1164.     while (*s) {
  1165.         digval = *s++;
  1166.         if ((digval >= '0') && (digval <= '9'))
  1167.             digval -= '0';
  1168.         else if ((digval >= 'a') && (digval <= 'f') && shift)
  1169.             digval -= ('a' - 10);
  1170.         else if ((digval >= 'A') && (digval <= 'F') && shift)
  1171.             digval -= ('A' - 10);
  1172.         else if (digval == '.')
  1173.             continue;
  1174.         else
  1175.             break;
  1176.         if (shift)
  1177.             zshift(z, shift, &ztmp);
  1178.         else
  1179.             zmuli(z, 10L, &ztmp);
  1180.         freeh(z.v);
  1181.         zadd(ztmp, digit, &z);
  1182.         freeh(ztmp.v);
  1183.     }
  1184.     trim(&z);
  1185.     if (minus && !iszero(z))
  1186.         z.sign = 1;
  1187.     *res = z;
  1188. }
  1189.  
  1190.  
  1191. /*
  1192.  * Parse a number in any of the various legal forms, and return the count
  1193.  * of characters that are part of a legal number.  Numbers can be either a
  1194.  * decimal integer, possibly two decimal integers separated with a slash, a
  1195.  * floating point or exponential number, a hex number beginning with "0x",
  1196.  * a binary number beginning with "0b", or an octal number beginning with "0".
  1197.  * The flags argument modifies the end of number testing for ease in handling
  1198.  * fractions or complex numbers.  Minus one is returned if the number format
  1199.  * is definitely illegal.
  1200.  */
  1201. long
  1202. qparse(cp, flags)
  1203.     register char *cp;
  1204. {
  1205.     char *oldcp;
  1206.  
  1207.     oldcp = cp;
  1208.     if ((*cp == '+') || (*cp == '-'))
  1209.         cp++;
  1210.     if ((*cp == '+') || (*cp == '-'))
  1211.         return -1;
  1212.     if ((*cp == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {    /* hex */
  1213.         cp += 2;
  1214.         while (((*cp >= '0') && (*cp <= '9')) ||
  1215.             ((*cp >= 'a') && (*cp <= 'f')) ||
  1216.             ((*cp >= 'A') && (*cp <= 'F')))
  1217.                 cp++;
  1218.         goto done;
  1219.     }
  1220.     if ((*cp == '0') && ((cp[1] == 'b') || (cp[1] == 'B'))) {    /* binary */
  1221.         cp += 2;
  1222.         while ((*cp == '0') || (*cp == '1'))
  1223.             cp++;
  1224.         goto done;
  1225.     }
  1226.     if ((*cp == '0') && (cp[1] >= '0') && (cp[1] <= '9')) { /* octal */
  1227.         while ((*cp >= '0') && (*cp <= '7'))
  1228.             cp++;
  1229.         goto done;
  1230.     }
  1231.     /*
  1232.      * Number is decimal, but can still be a fraction or real or exponential.
  1233.      */
  1234.     while ((*cp >= '0') && (*cp <= '9'))
  1235.         cp++;
  1236.     if (*cp == '/' && flags & QPF_SLASH) {    /* fraction */
  1237.         cp++;
  1238.         while ((*cp >= '0') && (*cp <= '9'))
  1239.             cp++;
  1240.         goto done;
  1241.     }
  1242.     if (*cp == '.') {    /* floating point */
  1243.         cp++;
  1244.         while ((*cp >= '0') && (*cp <= '9'))
  1245.             cp++;
  1246.     }
  1247.     if ((*cp == 'e') || (*cp == 'E')) {    /* exponential */
  1248.         cp++;
  1249.         if ((*cp == '+') || (*cp == '-'))
  1250.             cp++;
  1251.         if ((*cp == '+') || (*cp == '-'))
  1252.             return -1;
  1253.         while ((*cp >= '0') && (*cp <= '9'))
  1254.             cp++;
  1255.     }
  1256.  
  1257. done:
  1258.     if (((*cp == 'i') || (*cp == 'I')) && (flags & QPF_IMAG))
  1259.         cp++;
  1260.     if ((*cp == '.') || ((*cp == '/') && (flags & QPF_SLASH)) ||
  1261.         ((*cp >= '0') && (*cp <= '9')) ||
  1262.         ((*cp >= 'a') && (*cp <= 'z')) ||
  1263.         ((*cp >= 'A') && (*cp <= 'Z')))
  1264.             return -1;
  1265.     return (cp - oldcp);
  1266. }
  1267.  
  1268. /* END CODE */
  1269.